package com.wolfking.converter.web;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.google.common.collect.Sets;
import com.wolfking.converter.config.ClassnameConfig;
import com.wolfking.converter.entity.SqlDefine;
import com.wolfking.converter.entity.SqlDefineParam;
import com.wolfking.converter.event.SqlDefineParamEvent;
import com.wolfking.converter.service.SqlDefineParamService;
import com.wolfking.converter.service.SqlDefineService;
import com.wolfking.jeesite.config.SsoConfig;
import com.wolfking.jeesite.entity.PageInfo;
import com.wolfking.jeesite.sign.Sign;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.servlet.mvc.support.RedirectAttributes;

import java.net.URLEncoder;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;

@Slf4j
@Controller
@RequestMapping("/sql/parameter")
public class SqlParameterController {

    @Autowired
    private SqlDefineService defineService;

    @Autowired
    private SqlDefineParamService sqlDefineParamService;

    @Autowired
    private SsoConfig ssoConfig;

    @Autowired
    private ClassnameConfig classnameConfig;

    @Sign(code = "sql:parameter:view")
    @RequestMapping(value = "/list", method = {RequestMethod.GET, RequestMethod.POST})
    public String list(Model model,
                       @RequestParam(required = false, defaultValue = "") String defineKey,
                       @RequestParam(defaultValue = "", required = false) String paramName,
                       @RequestParam(defaultValue = "", required = false) String paramDescribe,
                       @RequestParam(defaultValue = "1") int pageNum,
                       @RequestParam(defaultValue = "30") int pageSize) {
        List<SqlDefine> defineList = defineService.list();
        SqlDefineParam sqlDefineParam = new SqlDefineParam();
        sqlDefineParam.setDefineKey(defineKey);
        sqlDefineParam.setParamName(paramName);
        sqlDefineParam.setParamDescribe(paramDescribe);
        QueryWrapper<SqlDefineParam> queryWrapper = sqlDefineParamService.queryWrapperConfig(sqlDefineParam,
                Sets.newHashSet("defineKey"), Sets.newHashSet("paramName", "paramDescribe"));
        if (StringUtils.isNotBlank(defineKey) &&
                StringUtils.isBlank(paramName) && StringUtils.isBlank(paramDescribe)) {
            queryWrapper.orderByAsc("sort");
        } else {
            queryWrapper.orderByDesc("id");
        }
        PageInfo<SqlDefineParam> page = sqlDefineParamService.pageQuery(queryWrapper, pageNum, pageSize);
        model.addAttribute("defineList", defineList);
        model.addAttribute("page", page);
        model.addAttribute("parameter", sqlDefineParam);
        model.addAttribute("defineMap", defineList.stream().collect(
                Collectors.toMap(SqlDefine::getDefineKey, SqlDefine::getSqlDescribe)));
        return "sql/parameter/list";
    }


    @Sign(code = "sql:parameter:view")
    @RequestMapping(value = "/edit", method = {RequestMethod.GET})
    public String editGet(Model model, @RequestParam(name = "id", required = false) Integer id,
                          @RequestParam(name = "defineKey", required = false) String defineKey) {
        List<SqlDefine> defineList = defineService.list();
        model.addAttribute("defineList", defineList);
        if (Objects.nonNull(id)) {
            SqlDefineParam byId = sqlDefineParamService.getById(id);
            if (Objects.isNull(byId)) {
                byId = new SqlDefineParam();
            }
            model.addAttribute("parameter", byId);
        } else {
            final SqlDefineParam sqlDefineParam = new SqlDefineParam();
            if (StringUtils.isNotBlank(defineKey)) {
                sqlDefineParam.setDefineKey(defineKey);
            }
            model.addAttribute("parameter", sqlDefineParam);
        }
        model.addAttribute("converterClassnames", classnameConfig.getTransformClassSet());
        model.addAttribute("dropdownClassnames", classnameConfig.getDropDownClassSet());
        return "sql/parameter/edit";
    }


    @Sign(code = "sql:parameter:edit", event = SqlDefineParamEvent.class)
    @RequestMapping(value = "/edit", method = {RequestMethod.POST})
    public String editPost(RedirectAttributes redirectAttributes, SqlDefineParam data) throws Exception {

        if (StringUtils.isNotBlank(data.getFormat())) {
            data.setFormat(data.getFormat().trim());
        }
        if (StringUtils.isNotBlank(data.getDropDown())) {
            data.setDropDown(data.getDropDown().trim());
        }
        if (Objects.isNull(data.getId())) {
            sqlDefineParamService.save(data);
            redirectAttributes.addFlashAttribute("message", "添加参数成功");
        } else {
            redirectAttributes.addFlashAttribute("message", "修改参数成功");
            sqlDefineParamService.updateById(data);
        }
        return ssoConfig.getRedirectWithPath(String.format("/sql/parameter/list?defineKey=%s&paramName=%s",
                URLEncoder.encode(data.getDefineKey(), "UTF-8"), URLEncoder.encode(data.getParamName(), "UTF-8")));
    }

    @Sign(code = "sql:parameter:edit")
    @RequestMapping(value = "/pageParam", method = {RequestMethod.GET})
    public String pageParam(RedirectAttributes redirectAttributes, @RequestParam String defineKey) throws Exception {

        SqlDefine sqlDefine = new SqlDefine();
        sqlDefine.setDefineKey(defineKey);
        if (CollectionUtils.isNotEmpty(defineService.selectExample(sqlDefine))) {
            try {
                int count = 0;
                SqlDefineParam sqlDefineParam = new SqlDefineParam();
                sqlDefineParam.setDefineKey(defineKey);
                sqlDefineParam.setPageNum(true);
                List<SqlDefineParam> sqlDefineParams = sqlDefineParamService.selectExample(sqlDefineParam);
                if (CollectionUtils.isEmpty(sqlDefineParams)) {
                    SqlDefineParam sqlDefineParamPageNum = new SqlDefineParam();
                    sqlDefineParamPageNum.setDefineKey(defineKey);
                    sqlDefineParamPageNum.setParamName("pageNum");
                    sqlDefineParamPageNum.setParamDescribe("页码");
                    sqlDefineParamPageNum.setPageNum(true);
                    sqlDefineParamPageNum.setDefaultValue("1");
                    sqlDefineParamPageNum.setParamType(Integer.class.getName());
                    sqlDefineParamPageNum.setSort(-1);
                    sqlDefineParamService.save(sqlDefineParamPageNum);
                    count++;
                }
                sqlDefineParam.setPageNum(null);
                sqlDefineParam.setPageSize(true);
                sqlDefineParams = sqlDefineParamService.selectExample(sqlDefineParam);
                if (CollectionUtils.isEmpty(sqlDefineParams)) {
                    SqlDefineParam sqlDefineParamPageSize = new SqlDefineParam();
                    sqlDefineParamPageSize.setDefineKey(defineKey);
                    sqlDefineParamPageSize.setParamName("pageSize");
                    sqlDefineParamPageSize.setParamDescribe("页大小");
                    sqlDefineParamPageSize.setPageSize(true);
                    sqlDefineParamPageSize.setDefaultValue("30");
                    sqlDefineParamPageSize.setParamType(Integer.class.getName());
                    sqlDefineParamPageSize.setSort(-1);
                    sqlDefineParamService.save(sqlDefineParamPageSize);
                    count++;
                }
                if (count > 0) {
                    redirectAttributes.addFlashAttribute("message", "添加分页参数成功");
                } else {
                    redirectAttributes.addFlashAttribute("message", "已经存在分页参数");
                }
            } catch (Exception e) {
                redirectAttributes.addFlashAttribute("message", "添加分页参数失败");
            }
        } else {
            redirectAttributes.addFlashAttribute("message", "SQL定义不存在");
        }


        return ssoConfig.getRedirectWithPath(String.format("/sql/parameter/list?defineKey=%s",
                URLEncoder.encode(defineKey, "UTF-8")));
    }

    @Sign(code = "sql:parameter:edit")
    @RequestMapping(value = "/updateSort")
    public String updateSort(String[] ids, String[] sorts, RedirectAttributes redirectAttributes) {
        for (int i = 0; i < ids.length; i++) {
            SqlDefineParam sqlDefineParam = new SqlDefineParam();
            sqlDefineParam.setId(Integer.parseInt(ids[i].replace(",", "")));
            sqlDefineParam.setSort(Integer.parseInt(sorts[i].replace(",", "")));
            sqlDefineParamService.updateSort(sqlDefineParam);
        }
        List<SqlDefineParam> sqlDefineParams =
                sqlDefineParamService.listByIds(Arrays.stream(ids).map(Integer::parseInt).collect(Collectors.toSet()));
        Set<String> defineKeySet = sqlDefineParams.stream().map(SqlDefineParam::getDefineKey).collect(Collectors.toSet());
        redirectAttributes.addFlashAttribute("message", "保存参数排序成功");
        if (defineKeySet.size() != 1) {
            return ssoConfig.getRedirectWithPath("/sql/parameter/list");
        } else {
            return ssoConfig.getRedirectWithPath("/sql/parameter/list?defineKey=" + defineKeySet.iterator().next());
        }
    }


    @Sign(code = "sql:parameter:edit")
    @RequestMapping(value = "/delete", method = {RequestMethod.GET})
    public String delete(RedirectAttributes redirectAttributes, @RequestParam("id") Integer id) {

        SqlDefineParam sqlDefineParam = sqlDefineParamService.getById(id);
        if (sqlDefineParam == null) {
            redirectAttributes.addFlashAttribute("messageType", "danger");
            redirectAttributes.addFlashAttribute("message", "数据不存在");
        } else {
            SqlDefine sqlDefine = new SqlDefine();
            sqlDefine.setDefineKey(sqlDefineParam.getDefineKey());
            List<SqlDefine> sqlDefines = defineService.selectExample(sqlDefine);
            if (sqlDefines.size() > 0) {
                sqlDefine = sqlDefines.get(0);
                String sqlBase64 = sqlDefine.getSqlBase64Decode();
                String countSqlBase64 = sqlDefine.getCountSqlBase64Decode();
                boolean contains = sqlBase64.contains("{{" + sqlDefineParam.getParamName() + "}}");
                if (!contains) {
                    contains = sqlBase64.contains(":" + sqlDefineParam.getParamName() + " ");
                }
                if (!contains) {
                    contains = sqlBase64.contains(":" + sqlDefineParam.getParamName() + "\n");
                }
                if (!contains) {
                    contains = countSqlBase64.contains("{{" + sqlDefineParam.getParamName() + "}}");
                }
                if (!contains) {
                    contains = countSqlBase64.contains(":" + sqlDefineParam.getParamName() + " ");
                }
                if (!contains) {
                    contains = countSqlBase64.contains(":" + sqlDefineParam.getParamName() + "\n");
                }
                if (contains) {
                    redirectAttributes.addFlashAttribute("messageType", "danger");
                    redirectAttributes.addFlashAttribute("message", "参数存在绑定，无法删除");
                } else {
                    sqlDefineParamService.deleteById(id);
                    redirectAttributes.addFlashAttribute("message", "删除SQL参数成功");
                }
            } else {
                sqlDefineParamService.deleteById(id);
                redirectAttributes.addFlashAttribute("message", "删除SQL查询成功");
            }
        }
        if (Objects.nonNull(sqlDefineParam)) {
            return ssoConfig.getRedirectWithPath("/sql/parameter/list?defineKey=" + sqlDefineParam.getDefineKey());
        } else {
            return ssoConfig.getRedirectWithPath("/sql/parameter/list");
        }
    }

}
